home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / hamradio / tnos-2.000 / tnos-2 / ip.c < prev    next >
C/C++ Source or Header  |  1996-07-13  |  14KB  |  569 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "netuser.h"
  11. #include "iface.h"
  12. #include "pktdrvr.h"
  13. #include "icmp.h"
  14.  
  15. #if !defined(_lint) && !defined(MSDOS)
  16. static char rcsid[] OPTIONAL = "$Id: ip.c,v 1.10 1996/07/14 02:59:57 root Exp root $";
  17. #endif
  18.  
  19. static struct mbuf *fraghandle __ARGS ((struct ip * ip, struct mbuf * bp));
  20. static void ip_timeout __ARGS ((void *arg));
  21. static void free_reasm __ARGS ((struct reasm * rp));
  22. static void freefrag __ARGS ((struct frag * fp));
  23. static struct reasm *lookup_reasm __ARGS ((struct ip * ip));
  24. static struct reasm *creat_reasm __ARGS ((struct ip * ip));
  25. static struct frag *newfrag __ARGS ((int16 offset, int16 last, struct mbuf * bp));
  26.  
  27. struct mib_entry Ip_mib[20] =
  28. {
  29.     { "",            {0} },
  30.     { "ipForwarding",    {1} },
  31.     { "ipDefaultTTL",    {MAXTTL} },
  32.     { "ipInReceives",    {0} },
  33.     { "ipInHdrErrors",    {0} },
  34.     { "ipInAddrErrors",    {0} },
  35.     { "ipForwDatagrams",    {0} },
  36.     { "ipInUnknownProtos",    {0} },
  37.     { "ipInDiscards",    {0} },
  38.     { "ipInDelivers",    {0} },
  39.     { "ipOutRequests",    {0} },
  40.     { "ipOutDiscards",    {0} },
  41.     { "ipOutNoRoutes",    {0} },
  42.     { "ipReasmTimeout",    {TLB} },
  43.     { "ipReasmReqds",    {0} },
  44.     { "ipReasmOKs",        {0} },
  45.     { "ipReasmFails",    {0} },
  46.     { "ipFragOKs",        {0} },
  47.     { "ipFragFails",    {0} },
  48.     { "ipFragCreates",    {0} },
  49. };
  50.  
  51.  
  52. struct reasm *Reasmq;
  53. struct raw_ip *Raw_ip;
  54.  
  55. #define    INSERT    0
  56. #define    APPEND    1
  57. #define    PREPEND    2
  58.  
  59.  
  60.  
  61. /* Send an IP datagram. Modeled after the example interface on p 32 of
  62.  * RFC 791
  63.  */
  64. int
  65. ip_send (source, dest, protocol, tos, ttl, bp, length, id, df)
  66. uint32 source;            /* source address */
  67. uint32 dest;            /* Destination address */
  68. char protocol;            /* Protocol */
  69. char tos;            /* Type of service */
  70. char ttl;            /* Time-to-live */
  71. struct mbuf *bp;        /* Data portion of datagram */
  72. int16 length;            /* Optional length of data portion */
  73. int16 id;            /* Optional identification */
  74. char df;            /* Don't-fragment flag */
  75. {
  76. struct mbuf *tbp;
  77. struct ip ip;        /* IP header */
  78. static int16 id_cntr = 0;    /* Datagram serial number */
  79. struct phdr phdr;
  80.  
  81.     ipOutRequests++;
  82.  
  83.     if (source == INADDR_ANY)
  84.         source = locaddr (dest);
  85.     if (length == 0 && bp != NULLBUF)
  86.         length = len_p (bp);
  87.     if (id == 0)
  88.         id = id_cntr++;
  89.     if (ttl == 0)
  90.         ttl = (char) ipDefaultTTL;
  91.  
  92.     /* Fill in IP header */
  93.     ip.version = IPVERSION;
  94.     ip.tos = tos;
  95.     ip.length = IPLEN + length;
  96.     ip.id = id;
  97.     ip.offset = 0;
  98.     ip.flags.mf = 0;
  99.     ip.flags.df = df;
  100.     ip.flags.congest = 0;
  101.     ip.ttl = ttl;
  102.     ip.protocol = protocol;
  103.     ip.source = source;
  104.     ip.dest = dest;
  105.     ip.optlen = 0;
  106.     if ((tbp = htonip (&ip, bp, IP_CS_NEW)) == NULLBUF) {
  107.         free_p (bp);
  108.         return -1;
  109.     }
  110.     if ((bp = pushdown (tbp, sizeof (phdr))) == NULLBUF) {
  111.         free_p (tbp);
  112.         return -1;
  113.     }
  114.     if (ismyaddr (ip.dest)) {
  115.         /* Pretend it has been sent by the loopback interface before
  116.          * it appears in the receive queue
  117.          */
  118.         phdr.iface = &Loopback;
  119.         Loopback.ipsndcnt++;
  120.         Loopback.rawsndcnt++;
  121.         Loopback.lastsent = secclock ();
  122.     } else
  123.         phdr.iface = NULLIF;
  124.     phdr.type = CL_NONE;
  125.     memcpy (&bp->data[0], (char *) &phdr, sizeof (phdr));
  126.     enqueue (&Hopper, bp);
  127.     return 0;
  128. }
  129.  
  130.  
  131.  
  132. /* Reassemble incoming IP fragments and dispatch completed datagrams
  133.  * to the proper transport module
  134.  */
  135. void
  136. ip_recv (iface, ip, bp, rxbroadcast)
  137. struct iface *iface;        /* Incoming interface */
  138. struct ip *ip;            /* Extracted IP header */
  139. struct mbuf *bp;        /* Data portion */
  140. int rxbroadcast;        /* True if received on subnet broadcast address */
  141. {
  142. /* Function to call with completed datagram */
  143. register struct raw_ip *rp;
  144. struct mbuf *bp1, *tbp;
  145. int rxcnt = 0;
  146. register struct iplink *ipp;
  147.  
  148.     /* If we have a complete packet, call the next layer
  149.      * to handle the result. Note that fraghandle passes back
  150.      * a length field that does NOT include the IP header
  151.      */
  152.     if ((bp = fraghandle (ip, bp)) == NULLBUF)
  153.         return;        /* Not done yet */
  154.  
  155.     ipInDelivers++;
  156.  
  157.     for (rp = Raw_ip; rp != NULLRIP; rp = rp->next) {
  158.         if (rp->protocol != ip->protocol)
  159.             continue;
  160.         rxcnt++;
  161.         /* Duplicate the data portion, and put the header back on */
  162.         (void) dup_p (&bp1, bp, 0, len_p (bp));
  163.         if (bp1 != NULLBUF && (tbp = htonip (ip, bp1, IP_CS_OLD)) != NULLBUF) {
  164.             enqueue (&rp->rcvq, tbp);
  165.             if (rp->r_upcall != NULLVFP ((struct raw_ip *)))
  166.                 (*rp->r_upcall) (rp);
  167.         } else {
  168.             free_p (bp1);
  169.         }
  170.     }
  171.     /* Look it up in the transport protocol table */
  172.     for (ipp = Iplink; ipp->funct != NULL; ipp++) {
  173.         if (ipp->proto == ip->protocol)
  174.             break;
  175.     }
  176.     if (ipp->funct != NULL) {
  177.         /* Found, call transport protocol */
  178.         (*ipp->funct) (iface, ip, bp, rxbroadcast);
  179.     } else {
  180.         /* Not found */
  181.         if (rxcnt == 0) {
  182.             /* Send an ICMP Protocol Unknown response... */
  183.             ipInUnknownProtos++;
  184.             /* ...unless it's a broadcast */
  185.             if (!rxbroadcast)
  186.                 (void) icmp_output (ip, bp, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, NULLICMP);
  187.         }
  188.         free_p (bp);
  189.     }
  190. }
  191.  
  192.  
  193.  
  194. #ifdef ENCAP
  195. /* Handle IP packets encapsulated inside IP */
  196. void
  197. ipip_recv (iface, ip, bp, rxbroadcast)
  198. struct iface *iface OPTIONAL;    /* Incoming interface */
  199. struct ip *ip OPTIONAL;        /* Extracted IP header */
  200. struct mbuf *bp;        /* Data portion */
  201. int rxbroadcast OPTIONAL;    /* True if received on subnet broadcast address */
  202. {
  203. struct phdr phdr;
  204. struct mbuf *tbp;
  205.  
  206.     if ((tbp = pushdown (bp, sizeof (phdr))) == NULLBUF) {
  207.         free_p (bp);
  208.         return;
  209.     }
  210.     bp = tbp;
  211.     phdr.iface = &Encap;
  212.     phdr.type = CL_NONE;
  213.     memcpy (&bp->data[0], (char *) &phdr, sizeof (phdr));
  214.     enqueue (&Hopper, bp);
  215. }
  216. #endif
  217.  
  218.  
  219.  
  220. /* Process IP datagram fragments
  221.  * If datagram is complete, return it with ip->length containing the data
  222.  * length (MINUS header); otherwise return NULLBUF
  223.  */
  224. static
  225. struct mbuf *
  226. fraghandle (ip, bp)
  227. struct ip *ip;            /* IP header, host byte order */
  228. struct mbuf *bp;        /* The fragment itself */
  229. {
  230. register struct reasm *rp;    /* Pointer to reassembly descriptor */
  231. struct frag *lastfrag, *nextfrag, *tfp;
  232. struct mbuf *tbp;
  233. int16 i;
  234. int16 last;        /* Index of first byte beyond fragment */
  235.  
  236.     last = (int16) (ip->offset + ip->length - (IPLEN + ip->optlen));
  237.  
  238.     rp = lookup_reasm (ip);
  239.     if (ip->offset == 0 && !ip->flags.mf) {
  240.         /* Complete datagram received. Discard any earlier fragments */
  241.         if (rp != NULLREASM) {
  242.             free_reasm (rp);
  243.             ipReasmOKs++;
  244.         }
  245.         return bp;
  246.     }
  247.     ipReasmReqds++;
  248.     if (rp == NULLREASM) {
  249.         /* First fragment; create new reassembly descriptor */
  250.         if ((rp = creat_reasm (ip)) == NULLREASM) {
  251.             /* No space for descriptor, drop fragment */
  252.             ipReasmFails++;
  253.             free_p (bp);
  254.             return NULLBUF;
  255.         }
  256.     }
  257.     /* Keep restarting timer as long as we keep getting fragments */
  258.     stop_timer (&rp->timer);
  259.     start_timer (&rp->timer);
  260.  
  261.     /* If this is the last fragment, we now know how long the
  262.      * entire datagram is; record it
  263.      */
  264.     if (!ip->flags.mf)
  265.         rp->length = last;
  266.  
  267.     /* Set nextfrag to the first fragment which begins after us,
  268.      * and lastfrag to the last fragment which begins before us
  269.      */
  270.     lastfrag = NULLFRAG;
  271.     for (nextfrag = rp->fraglist; nextfrag != NULLFRAG; nextfrag = nextfrag->next) {
  272.         if (nextfrag->offset > ip->offset)
  273.             break;
  274.         lastfrag = nextfrag;
  275.     }
  276.     /* Check for overlap with preceeding fragment */
  277.     if (lastfrag != NULLFRAG && ip->offset < lastfrag->last) {
  278.         /* Strip overlap from new fragment */
  279.         i = lastfrag->last - ip->offset;
  280.         (void) pullup (&bp, (unsigned char *) 0, i);
  281.         if (bp == NULLBUF)
  282.             return NULLBUF;    /* Nothing left */
  283.         ip->offset += i;
  284.     }
  285.     /* Look for overlap with succeeding segments */
  286.     for (; nextfrag != NULLFRAG; nextfrag = tfp) {
  287.         tfp = nextfrag->next;    /* save in case we delete fp */
  288.  
  289.         if (nextfrag->offset >= last)
  290.             break;    /* Past our end */
  291.         /* Trim the front of this entry; if nothing is
  292.          * left, remove it.
  293.          */
  294.         i = last - nextfrag->offset;
  295.         (void) pullup (&nextfrag->buf, (unsigned char *) 0, i);
  296.         if (nextfrag->buf == NULLBUF) {
  297.             /* superseded; delete from list */
  298.             if (nextfrag->prev != NULLFRAG)
  299.                 nextfrag->prev->next = nextfrag->next;
  300.             else
  301.                 rp->fraglist = nextfrag->next;
  302.             if (tfp->next != NULLFRAG)
  303.                 nextfrag->next->prev = nextfrag->prev;
  304.             freefrag (nextfrag);
  305.         } else
  306.             nextfrag->offset = last;
  307.     }
  308.     /* Lastfrag now points, as before, to the fragment before us;
  309.      * nextfrag points at the next fragment. Check to see if we can
  310.      * join to either or both fragments.
  311.      */
  312.     i = INSERT;
  313.     if (lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  314.         i |= APPEND;
  315.     if (nextfrag != NULLFRAG && nextfrag->offset == last)
  316.         i |= PREPEND;
  317.     /*lint -save -e613 */
  318.     switch (i) {
  319.         case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  320.             tfp = newfrag (ip->offset, last, bp);
  321.             tfp->prev = lastfrag;
  322.             tfp->next = nextfrag;
  323.             if (lastfrag != NULLFRAG)
  324.                 lastfrag->next = tfp;    /* Middle of list */
  325.             else
  326.                 rp->fraglist = tfp;    /* First on list */
  327.             if (nextfrag != NULLFRAG)
  328.                 nextfrag->prev = tfp;
  329.             break;
  330.         case APPEND:    /* Append to lastfrag */
  331.             append (&lastfrag->buf, bp);
  332.             lastfrag->last = last;    /* Extend forward */
  333.             break;
  334.         case PREPEND:    /* Prepend to nextfrag */
  335.             tbp = nextfrag->buf;
  336.             nextfrag->buf = bp;
  337.             append (&nextfrag->buf, tbp);
  338.             nextfrag->offset = ip->offset;    /* Extend backward */
  339.             break;
  340.         case (APPEND | PREPEND):
  341.             /* Consolidate by appending this fragment and nextfrag
  342.              * to lastfrag and removing the nextfrag descriptor
  343.              */
  344.             append (&lastfrag->buf, bp);
  345.             append (&lastfrag->buf, nextfrag->buf);
  346.             nextfrag->buf = NULLBUF;
  347.             lastfrag->last = nextfrag->last;
  348.  
  349.             /* Finally unlink and delete the now unneeded nextfrag */
  350.             lastfrag->next = nextfrag->next;
  351.             if (nextfrag->next != NULLFRAG)
  352.                 nextfrag->next->prev = lastfrag;
  353.             freefrag (nextfrag);
  354.             break;
  355.         default:
  356.             break;
  357.     }
  358.     /*lint -restore */
  359.     if (rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG && rp->length != 0) {
  360.         /* We've gotten a complete datagram, so extract it from the
  361.          * reassembly buffer and pass it on.
  362.          */
  363.         bp = rp->fraglist->buf;
  364.         rp->fraglist->buf = NULLBUF;
  365.         /* Tell IP the entire length */
  366.         ip->length = (int16) (rp->length + (IPLEN + ip->optlen));
  367.         free_reasm (rp);
  368.         ipReasmOKs++;
  369.         return bp;
  370.     } else
  371.         return NULLBUF;
  372. }
  373.  
  374.  
  375.  
  376. /* Arrange for receipt of raw IP datagrams */
  377. struct raw_ip *
  378. raw_ip (protocol, r_upcall)
  379. int protocol;
  380. void (*r_upcall) __ARGS ((struct raw_ip *));
  381. {
  382. register struct raw_ip *rp;
  383.  
  384.     rp = (struct raw_ip *) callocw (1, sizeof (struct raw_ip));
  385.  
  386.     rp->protocol = protocol;
  387.     rp->r_upcall = r_upcall;
  388.     rp->next = Raw_ip;
  389.     Raw_ip = rp;
  390.     return rp;
  391. }
  392.  
  393.  
  394.  
  395. /* Free a raw IP descriptor */
  396. void
  397. del_ip (struct raw_ip *rpp)
  398. {
  399. struct raw_ip *rplast = NULLRIP;
  400. register struct raw_ip *rp;
  401.  
  402.     /* Do sanity check on arg */
  403.     for (rp = Raw_ip; rp != NULLRIP; rplast = rp, rp = rp->next)
  404.         if (rp == rpp)
  405.             break;
  406.     if (rp == NULLRIP)
  407.         return;        /* Doesn't exist */
  408.  
  409.     /* Unlink */
  410.     if (rplast != NULLRIP)
  411.         rplast->next = rp->next;
  412.     else
  413.         Raw_ip = rp->next;
  414.     /* Free resources */
  415.     free_q (&rp->rcvq);
  416.     free ((char *) rp);
  417. }
  418.  
  419.  
  420.  
  421. static struct reasm *
  422. lookup_reasm (struct ip *ip)
  423. {
  424. register struct reasm *rp;
  425. struct reasm *rplast = NULLREASM;
  426.  
  427.     for (rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next) {
  428.         if (ip->id == rp->id && ip->source == rp->source && ip->dest == rp->dest && ip->protocol == rp->protocol) {
  429.             if (rplast != NULLREASM) {
  430.                 /* Move to top of list for speed */
  431.                 rplast->next = rp->next;
  432.                 rp->next = Reasmq;
  433.                 Reasmq = rp;
  434.             }
  435.             return rp;
  436.         }
  437.     }
  438.     return NULLREASM;
  439. }
  440.  
  441.  
  442.  
  443. /* Create a reassembly descriptor,
  444.  * put at head of reassembly list
  445.  */
  446. static struct reasm *
  447. creat_reasm (register struct ip *ip)
  448. {
  449. register struct reasm *rp;
  450.  
  451.     if ((rp = (struct reasm *) calloc (1, sizeof (struct reasm))) == NULLREASM)
  452.               return rp;/* No space for descriptor */
  453.  
  454.     rp->source = ip->source;
  455.     rp->dest = ip->dest;
  456.     rp->id = ip->id;
  457.     rp->protocol = ip->protocol;
  458.     set_timer (&rp->timer, (long) (ipReasmTimeout * 1000L));
  459.     rp->timer.func = ip_timeout;
  460.     rp->timer.arg = rp;
  461.  
  462.     rp->next = Reasmq;
  463.     Reasmq = rp;
  464.     return rp;
  465. }
  466.  
  467.  
  468.  
  469. /* Free all resources associated with a reassembly descriptor */
  470. static void
  471. free_reasm (struct reasm *r)
  472. {
  473. register struct reasm *rp;
  474. struct reasm *rplast = NULLREASM;
  475. register struct frag *fp;
  476.  
  477.     for (rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next)
  478.         if (r == rp)
  479.             break;
  480.     if (rp == NULLREASM)
  481.         return;        /* Not on list */
  482.  
  483.     stop_timer (&rp->timer);
  484.     /* Remove from list of reassembly descriptors */
  485.     if (rplast != NULLREASM)
  486.         rplast->next = rp->next;
  487.     else
  488.         Reasmq = rp->next;
  489.  
  490.     /* Free any fragments on list, starting at beginning */
  491.     while ((fp = rp->fraglist) != NULLFRAG) {
  492.         rp->fraglist = fp->next;
  493.         free_p (fp->buf);
  494.         free ((char *) fp);
  495.     }
  496.     free ((char *) rp);
  497. }
  498.  
  499.  
  500.  
  501. /* Handle reassembly timeouts by deleting all reassembly resources */
  502. static void
  503. ip_timeout (void *arg)
  504. {
  505. register struct reasm *rp;
  506.  
  507.     rp = (struct reasm *) arg;
  508.     free_reasm (rp);
  509.     ipReasmFails++;
  510. }
  511.  
  512.  
  513.  
  514. /* Create a fragment */
  515. static struct frag *
  516. newfrag (int16 offset, int16 last, struct mbuf *bp)
  517. {
  518. struct frag *fp;
  519.  
  520.     if ((fp = (struct frag *) calloc (1, sizeof (struct frag))) == NULLFRAG) {
  521.         /* Drop fragment */
  522.         free_p (bp);
  523.         return NULLFRAG;
  524.     }
  525.     fp->buf = bp;
  526.     fp->offset = offset;
  527.     fp->last = last;
  528.     return fp;
  529. }
  530.  
  531.  
  532.  
  533. /* Delete a fragment, return next one on queue */
  534. static void
  535. freefrag (struct frag *fp)
  536. {
  537.     free_p (fp->buf);
  538.     free ((char *) fp);
  539. }
  540.  
  541.  
  542.  
  543. #if !defined(UNIX) && !defined(TNOS_68K)
  544. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  545.  * each fragment on each reassembly descriptor
  546.  */
  547. void
  548. ip_garbage (int red)
  549. {
  550. struct reasm *rp, *rp1;
  551. struct frag *fp;
  552. struct raw_ip *rwp;
  553.  
  554.     /* Run through the reassembly queue */
  555.     for (rp = Reasmq; rp != NULLREASM; rp = rp1) {
  556.         rp1 = rp->next;
  557.         if (red)
  558.             free_reasm (rp);
  559.         else {
  560.             for (fp = rp->fraglist; fp != NULLFRAG; fp = fp->next)
  561.                 mbuf_crunch (&fp->buf);
  562.         }
  563.     }
  564.     /* Run through the raw IP queue */
  565.     for (rwp = Raw_ip; rwp != NULLRIP; rwp = rwp->next)
  566.         mbuf_crunch (&rwp->rcvq);
  567. }
  568. #endif
  569.